package com.hmkj.web.config;

import com.hmkj.boot.utils.SpringContextUtils;
import com.hmkj.core.constant.SessionId;
import com.hmkj.core.exception.BussinessException;
import com.hmkj.core.po.user.User;
import com.hmkj.core.service.cache.RedisService;
import com.hmkj.core.service.user.UserService;
import com.xiaoleilu.hutool.util.RandomUtil;
import com.xiaoleilu.hutool.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * 前台拦截器
 *
 * @author donfy
 * @date 2016/10/21
 */
@Slf4j
@Component
public class WebInterceptor implements HandlerInterceptor {

    private String[] uri;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 在请求处理之前进行调用（Controller方法调用之前）
        debugLog(request, handler);
        // 判断/创建本地sessionId
        String sid = createSession(request, response);
        // 登录校验
        doLogin(request, response, sid);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 请求处理之后进行调用，但是在视图被渲染之前（Controller方法调用之后）
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 在整个请求结束之后被调用，也就是在DispatcherServlet 渲染了对应的视图之后执行（主要是用于进行资源清理工作）

    }

    private String createSession(HttpServletRequest httpServletRequest, HttpServletResponse response) {
        String hid = httpServletRequest.getParameter(SessionId.COOKIE_SESSIONID);
        String userId = httpServletRequest.getParameter(SessionId.COOKIE_USERID);
        String sid = "SESSION:" + hid;
        RedisService redisService = SpringContextUtils.getBean(RedisService.class);

        // 判断user是否有hid  是否匹配 不匹配则继续 匹配则使用hid  是否含有userId
        if (StrUtil.isNotBlank(hid)) {
            if (StrUtil.isNotBlank(userId) && !redisService.mapHas(sid, SessionId.MEMBER_USER)) {
                UserService userService = SpringContextUtils.getBean(UserService.class);
                final User user = userService.selectByPrimaryKey(Integer.parseInt(userId));
                if (user != null && StrUtil.isNotBlank(user.getHid()) && user.getHid().equals(sid)) {
                    // 自动登录
                    redisService.mapPut(sid, SessionId.MEMBER_USER, user);
                }
            }
        } else {
            hid = RandomUtil.randomUUID();
            sid = "SESSION:" + hid;
        }
        // 30分钟有效期
        redisService.mapPut(sid, "mark", "1");
        redisService.expire(sid, 1800);
        httpServletRequest.setAttribute(SessionId.COOKIE_SESSIONID, hid);
        return sid;
    }

    private void doLogin(HttpServletRequest httpServletRequest, HttpServletResponse response, String sid) {
        // 未登陆校验
        String requestURI = httpServletRequest.getRequestURI();
        for (String u : this.uri) {
            // 需拦截的地址
            if (requestURI.contains(u)) {
                RedisService redisService = SpringContextUtils.getBean(RedisService.class);
                if (!redisService.mapHas(sid, SessionId.MEMBER_USER)) {
                    throw new BussinessException(BussinessException.Code.E401);
                }
                break;
            }
        }
    }

    private void debugLog(HttpServletRequest request, Object handler) {

        Thread.currentThread().getStackTrace();
        try {
            Class clazz = ((HandlerMethod) handler).getBean().getClass();
            Method m = ((HandlerMethod) handler).getMethod();
            StackTraceElement traces =
                    new StackTraceElement(clazz.getName(), m.getName(), clazz.getName(), 1);
            StringBuilder sb = new StringBuilder();
            sb.append("\n---------------------------------------------------------------------------------\n                   ")
                    .append(traces)
                    .append("\n          方法:     ")
                    .append(m.getName())
                    .append("\n          参数:     ");
            request.getParameterMap().forEach((k, v) -> sb.append(k).append("=").append(v[0]).append(" "));
            sb.append("\n--------------------------------------------------------------------------------");
            log.info(sb.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public WebInterceptor(String[] uri) {
        this.uri = uri;
    }

    public WebInterceptor() {
        super();
    }
}
